home *** CD-ROM | disk | FTP | other *** search
- From: argv@zipcode.com (Dan Heller)
- Newsgroups: comp.sources.misc
- Subject: v18i060: mush - Mail User's Shell, Part03/22
- Message-ID: <1991Apr21.024911.11147@sparky.IMD.Sterling.COM>
- Date: 21 Apr 91 02:49:11 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: b176fd44 0a91f5e5 91b5304d ff82ec68
-
- Submitted-by: Dan Heller <argv@zipcode.com>
- Posting-number: Volume 18, Issue 60
- Archive-name: mush/part03
- Supersedes: mush: Volume 12, Issue 28-47
-
- #!/bin/sh
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file addrs.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 3; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping addrs.c'
- else
- echo 'x - continuing file addrs.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'addrs.c' &&
- X p = sender + c;
- X *p++ = ',', *p++ = ' ';
- X (void) strcpy(p, next);
- X (void) strcpy(to, sender);
- }
- X
- /*
- X * pass a string describing header like, "Subject: ", current value, and
- X * whether or not to prompt for it or to just post the information.
- X * If do_prompt is true, "type in" the current value so user can either
- X * modify it, erase it, or add to it.
- X */
- char *
- set_header(str, curstr, do_prompt)
- register char *str, *curstr;
- {
- X static char buf[HDRSIZ];
- X int offset = 0;
- X register char *p = curstr;
- X
- X if (!str)
- X str = "";
- X
- X buf[0] = 0;
- X print(str);
- X (void) fflush(stdout); /* force str curstr */
- X if (do_prompt) {
- X if (curstr)
- X if (isoff(glob_flags, ECHO_FLAG)) {
- X Ungetstr(curstr);
- X } else
- #ifdef TIOCSTI
- X for (p = curstr; *p; p++)
- X if (ioctl(0, TIOCSTI, p) == -1) {
- X error("ioctl: TIOCSTI");
- X print("You must retype the entire line.\n%s", str);
- X break;
- X }
- #else /* !TIOCSTI */
- X print("WARNING: -e flag! Type the line over.\n%s", str);
- #endif /* TIOCSTI */
- X
- X if (istool)
- X return NULL;
- X /* simulate the fact that we're getting input for the letter even tho
- X * we may not be. set_header is called before IS_GETTING is true,
- X * but if we set it to true temporarily, then signals will return to
- X * the right place (stop/continue).
- X */
- X {
- X u_long getting = ison(glob_flags, IS_GETTING);
- X int wrapping = wrapcolumn;
- X /* Funky trick here. If the prompt string is empty,
- X * assume that we are allowed to do line wrap;
- X * otherwise, temporarily disable line wrap
- X */
- X if (*str)
- X wrapcolumn = 0;
- X if (!getting)
- X turnon(glob_flags, IS_GETTING);
- X if (Getstr(buf, sizeof(buf), offset) == -1) {
- X putchar('\n');
- X buf[0] = 0;
- X }
- X if (!getting)
- X turnoff(glob_flags, IS_GETTING);
- X wrapcolumn = wrapping;
- X }
- X } else
- X puts(strcpy(buf, curstr));
- X if (debug > 1)
- X print("returning (%s) from set_header\n", buf);
- X return buf;
- }
- X
- /*
- X * improve uucp paths by looking at the name of each host listed in the
- X * path given.
- X * sun!island!pixar!island!argv
- X * It's a legal address, but redundant. Also, if we know we talk to particular
- X * hosts via uucp, then we can just start with that host and disregard the path
- X * preceding it. So, first get the known hosts and save them. Then start
- X * at the end of the original path (at the last ! found), and move backwards
- X * saving each hostname. If we get to a host that we know about, stop there
- X * and use that address. If the system knows about domains, skip all paths
- X * that precede a domain hostname. If we get to a host we've already seen,
- X * then delete it and all the hosts since then until the first occurrence of
- X * that hostname. When we get to the beginning, the address will be complete.
- X * The route_path is prepended to each address to check make sure this path
- X * is used if no known_hosts precede it in that address.
- X *
- X * Return all results into the original buffer passed to us. If route_path
- X * adds to the length of all the paths, then the original buffer could be
- X * overwritten. someone should check for this!
- X */
- improve_uucp_paths(original, size, route_path)
- char *original, *route_path;
- {
- X char name[256], addr[256], buf[2 * HDRSIZ], *end;
- X char *hostnames[32], tmp[sizeof addr], *domain_path;
- X register char *p, *p2, *recipient, *start = original, *b = buf;
- X int saved_hosts, i, is_domain;
- X
- X if (!original || !*original)
- X return;
- X
- X /* use domain_path to point to the path for pathnames that have
- X * a fully qualified domain host in them.
- X */
- X domain_path = do_set(set_options, "domain_route");
- X while (end = get_name_n_addr(start, name, tmp)) {
- X /* first copy the route path, then the rest of the address. */
- X p = addr;
- X if (route_path && *route_path) {
- X p += Strcpy(addr, route_path);
- X *p++ = '!';
- X }
- X (void) bang_form(p, tmp);
- X saved_hosts = 0;
- X if (p2 = rindex(p, '!')) {
- X recipient = p2+1;
- X /* save the uucp-style address *without* route_path in tmp */
- X (void) strcpy(tmp, p);
- X for (p = p2; p > addr; p--) {
- X is_domain = 0;
- X /* null the '!' separating the rest of the path from the part
- X * of the path preceding it and move p back to the previous
- X * '!' (or beginning to addr) for hostname to point to.
- X */
- X for (*p-- = 0; p > addr && *p != '!'; p--)
- X if (!is_domain && domain_path && *p == '.' &&
- X lcase_strncmp(p, ".uucp", 5))
- X is_domain++;
- X /* if p is not at the addr, move it forward past the '!' */
- X if (p != addr)
- X ++p; /* now points to a null terminated hostname */
- X /* if host is ourselves, ignore this and preceding hosts */
- X for (i = 0; ourname && ourname[i]; i++)
- X if (!lcase_strncmp(p, ourname[i], -1))
- X break;
- X if (ourname && ourname[i]) {
- X is_domain = 0; /* we've eliminated all domains */
- X break;
- X }
- X /* check already saved hostnames. If host is one of them,
- X * delete remaining hostnames since there is a redundant path.
- X */
- X for (i = 0; i < saved_hosts; i++)
- X if (!lcase_strncmp(hostnames[i], p, -1))
- X saved_hosts = i;
- X
- X /* Add the hostname to the path being constructed */
- X hostnames[saved_hosts++] = p;
- X
- X /* If the original path or the address is a fully qualified
- X * hostname (domain info is included), then break here
- X */
- X if (p == addr || is_domain && domain_path)
- X break;
- X /* If we know that we call this host, break */
- X for (i = 0; known_hosts && known_hosts[i]; i++)
- X if (!lcase_strncmp(p, known_hosts[i], -1))
- X break;
- X if (known_hosts && known_hosts[i])
- X break;
- X }
- X /* temporary holder for where we are in buffer (save address) */
- X p2 = b;
- X if (is_domain && domain_path && *domain_path)
- X b += Strcpy(b, domain_path), *b++ = '!';
- X while (saved_hosts-- > 0) {
- X b += Strcpy(b, hostnames[saved_hosts]);
- X *b++ = '!';
- X }
- X b += Strcpy(b, recipient);
- X if (!strcmp(p2, tmp)) { /* if the same, address was unmodified */
- X b = p2; /* reset offset in buf (b) to where we were (p2) */
- X goto unmodified;
- X }
- X if (*name)
- X b += strlen(sprintf(b, " (%s)", name));
- X } else {
- X char c;
- unmodified:
- X c = *end;
- X *end = 0;
- X b += Strcpy(b, start); /* copy the entire address with comments */
- X *end = c;
- X }
- X if (b - buf > size) {
- X wprint("Warning: address list truncated!\n");
- X /* Use a very poor heuristic to find the last complete address */
- X for (b = buf+size - 1; *b != ','; b--)
- X ;
- X wprint("Lost addresses: %s%s\n", b, end); /* end = not yet parsed */
- X while (isspace(*b) || *b == ',')
- X b--;
- X break;
- X }
- X for (start = end; *start == ',' || isspace(*start); start++)
- X ;
- X if (!*start)
- X break;
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X }
- X (void) strcpy(original, buf);
- }
- X
- /*
- X * rm_cmts_in_addr() removes the comment lines in addresses that result from
- X * sendmail or other mailers which append the user's "real name" on the
- X * from lines. See get_name_n_addr().
- X */
- rm_cmts_in_addr(str)
- register char *str;
- {
- X char addr[BUFSIZ], buf[HDRSIZ], *start = str;
- X register char *b = buf;
- X
- X *b = 0;
- X do {
- X if (!(str = get_name_n_addr(str, NULL, addr)))
- X break;
- X b += Strcpy(b, addr);
- X while (*str == ',' || isspace(*str))
- X str++;
- X if (*str)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*str);
- X for (b--; b > start && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- }
- X
- /*
- X * take_me_off() is intended to search for the user's login name in an
- X * address string and remove it. If "metoo" is set, return without change.
- X * determine which addresses are the "user'"'s addresses by comparing them
- X * against the host/path names in alternates. If the "*" is used, then
- X * this matches the address against the user's current login and -any- path.
- X *
- X * Note that the alternates list is an array of addresses stored *reversed*!
- X */
- take_me_off(str)
- char *str;
- {
- X int i = 0, rm_me;
- X char tmp[256], addr[256], buf[HDRSIZ], *start = str;
- X register char *p, *p2, *b = buf;
- X
- X if (!str || !*str)
- X return;
- X
- X Debug("take_me_off()\n");
- X *b = 0;
- X do {
- X rm_me = FALSE;
- X /* get the first "address" and advance p to next addr (ignore name) */
- X if (!(p = get_name_n_addr(str, NULL, tmp)))
- X break; /* we've reached the end of the address list */
- X /* see if user's login is in the address */
- X if (!strcmp(login, tmp))
- X rm_me = TRUE;
- X else {
- X int len;
- X /* put address in !-format and store in "addr" */
- X (void) bang_form(addr, tmp);
- X (void) reverse(addr);
- X for (i = 0; alternates && alternates[i] && !rm_me; i++) {
- X if (alternates[i][0] == '*') {
- X if (alternates[i][1] == '\0')
- X p2 = reverse(strcpy(tmp, login));
- X else
- X p2 = reverse(strcpy(tmp, &alternates[i][1]));
- X } else
- X p2 = alternates[i];
- X if (!lcase_strncmp(p2, addr, (len = strlen(p2))) &&
- X (!addr[len] || addr[len] == '!')) {
- X Debug("\t%s\n", reverse(addr));
- X rm_me = TRUE;
- X }
- X }
- X for (i = 0; !rm_me && ourname && ourname[i]; i++) {
- X p2 = tmp + Strcpy(tmp, ourname[i]);
- X *p2++ = '!';
- X (void) strcpy(p2, login);
- X (void) reverse(tmp);
- X if (!lcase_strncmp(tmp, addr, (len = strlen(tmp))) &&
- X (!addr[len] || addr[len] == '!')) {
- X Debug("\t%s\n", reverse(addr));
- X rm_me = TRUE;
- X }
- X }
- X }
- X /* The address is not the user's -- put it into the returned list */
- X if (!rm_me) {
- X char c = *p;
- X *p = 0;
- X b += Strcpy(b, str);
- X *p = c;
- X }
- X while (*p == ',' || isspace(*p))
- X p++;
- X if (*p && !rm_me)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- }
- X
- /*
- X * Place commas in between all addresses that don't already have
- X * them. Addresses which use comments which are in parens or _not_
- X * within angle brackets *must* already have commas around them or
- X * you can't determine what is a comment and what is an address.
- X */
- fix_up_addr(str)
- char *str;
- {
- X char buf[HDRSIZ], *start = str;
- X register char c, *p, *b = buf;
- X
- X *b = 0;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(str, NULL, NULL)))
- X break;
- X c = *p, *p = 0;
- X if (strlen(str) + (b - buf) >= sizeof(buf) - 2) {
- X /* wprint("Address too long! Lost address: \"%s\"\n", str); */
- X *p = c;
- X break;
- X }
- X for (b += Strcpy(b, str); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X if (*p)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- }
- X
- /*
- X * Remove redundant addresses.
- X * Assume improve_uucp_paths, fix_up_addr or whatever have already been called.
- X */
- rm_redundant_addrs(to, cc)
- char *to, *cc;
- {
- X char tmp[256], addr[256], buf[HDRSIZ];
- X char **list; /* a list of addresses for comparison */
- X int list_cnt = 0, l;
- X register char c, *p, *b, *start;
- X
- X Debug("rm_redundant_addrs()\n");
- X list = (char **) calloc(256, sizeof(char *));
- X if (!list) {
- X error("out of memory in rm_redundant_addrs");
- X return;
- X }
- X start = to;
- X b = buf, *b = 0;
- X /* first do the To header */
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(to, NULL, tmp)))
- X break;
- X c = *p, *p = 0;
- X (void) bang_form(addr, tmp);
- X for (l = 0; l < list_cnt; l++)
- X if (!lcase_strncmp(addr, list[l], -1))
- X break;
- X /* if l == list_cnt, we got a new address, store it and add to buf */
- X if (l == list_cnt) {
- X /* Don't overwrite buffer. */
- X if (list_cnt < 256)
- X list[list_cnt++] = savestr(addr);
- X if (b > buf)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X for (b += Strcpy(b, to); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X } else
- X Debug("\t%s\n", tmp); /* already specified (removed from list) */
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(to = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X b = buf, *b = 0;
- X /* Now do the Cc header. If addr is listed in the To field, rm it in cc */
- X start = cc;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(cc, NULL, tmp)))
- X break;
- X c = *p, *p = 0;
- X (void) bang_form(addr, tmp);
- X for (l = 0; l < list_cnt; l++)
- X if (!lcase_strncmp(addr, list[l], -1))
- X break;
- X if (l == list_cnt) {
- X /* Don't overwrite buffer. */
- X if (list_cnt < sizeof(list)/sizeof(char *))
- X list[list_cnt++] = savestr(addr);
- X if (b > buf)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X for (b += Strcpy(b, cc); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X } else
- X Debug("\t%s\n", tmp); /* already specified (removed from list) */
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(cc = p));
- X list[list_cnt] = NULL; /* for free_vec */
- X free_vec(list);
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- }
- X
- /*
- X * Get address and name from a string (str) which came from an address header
- X * in a message or typed by the user. The string may contain one or more
- X * well-formed addresses. Each must be separated by a comma.
- X *
- X * address, address, address
- X * address (comment or name here)
- X * comment or name <address>
- X * "Comment, even those with comma's!" <address>
- X * address (comma, (more parens), etc...)
- X *
- X * This does *not* handle cases like:
- X * comment <address (comment)>
- X *
- X * find the *first* address here and return a pointer to the end of the
- X * address (usually a comma). Return NULL on error: non-matching parens,
- X * brackets, quotes...
- X */
- char *
- get_name_n_addr(str, name, addr)
- register char *str, *name, *addr;
- {
- X register char *p, *p2, *beg_addr = addr, *beg_name = name, c;
- X
- X if (addr)
- X *addr = 0;
- X if (name)
- X *name = 0;
- X if (!str || !*str)
- X return NULL;
- X
- X while (isspace(*str))
- X str++;
- X
- X /* first check to see if there's something to look for */
- X if (!(p = any(str, ",(<\""))) {
- X /* no comma or indication of a quote character. Find a space and
- X * return that. If nothing, the entire string is a complete address
- X */
- X if (p = any(str, " \t"))
- X c = *p, *p = 0;
- X if (addr)
- X (void) strcpy(addr, str);
- X if (p)
- X *p = c;
- X return p? p : str + strlen(str);
- X }
- X
- X /* comma terminated before any comment stuff. If so, check for whitespace
- X * before-hand cuz it's possible that strings aren't comma separated yet
- X * and they need to be.
- X *
- X * address address address, address
- X * ^p <- p points here.
- X * ^p2 <- should point here.
- X */
- X if (*p == ',') {
- X c = *p, *p = 0;
- X if (p2 = any(str, " \t"))
- X *p = ',', c = *p2, p = p2, *p = 0;
- X if (addr)
- X (void) strcpy(addr, str);
- X *p = c;
- X return p;
- X }
- X
- X /* starting to get hairy -- we found an angle bracket. This means that
- X * everything outside of those brackets are comments until we find that
- X * all important comma. A comment AFTER the <addr> :
- X * <address> John Doe
- X * can't call this function recursively or it'll think that "John Doe"
- X * is a string with two legal address on it (each name being an address).
- X */
- X if (*p == '<') { /* note that "str" still points to comment stuff! */
- X if (name && *str) {
- X *p = 0;
- X name += Strcpy(name, str);
- X *p = '<';
- X }
- X if (!(p2 = index(p+1, '>'))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (addr) {
- X /* to support <addr (comment)> style addresses, add code here */
- X *p2 = 0;
- X skipspaces(1);
- X addr += Strcpy(addr, p);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p2 = '>';
- X }
- X /* take care of the case "... <addr> com (ment)" */
- X {
- X int p_cnt = 0; /* parenthesis counter */
- X p = p2;
- X /* don't recurse yet -- scan till null, comma or '<'(add to name) */
- X for (p = p2; p[1] && (p_cnt || p[1] != ',' && p[1] != '<'); p++) {
- X if (p[1] == '(')
- X p_cnt++;
- X else if (p[1] == ')')
- X p_cnt--;
- X if (name)
- X *name++ = p[1];
- X }
- X if (p_cnt) {
- X wprint("Warning! Malformed name: \"%s\"\n", name);
- X return NULL;
- X }
- X }
- X if (name && name > beg_name) {
- X while (isspace(*(name-1)))
- X --name;
- X *name = 0;
- X }
- X }
- X
- X /* this is the worst -- now we have parentheses/quotes. These guys can
- X * recurse pretty badly and contain commas within them.
- X */
- X if (*p == '(' || *p == '"') {
- X char *start = p;
- X int comment = 1;
- X c = *p;
- X /* "str" points to address while p points to comments */
- X if (addr && *str) {
- X *p = 0;
- X while (isspace(*str))
- X str++;
- X addr += Strcpy(addr, str);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p = c;
- X }
- X while (comment) {
- X if (c == '"' && !(p = index(p+1, '"')) ||
- X c == '(' && !(p = any(p+1, "()"))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (*p == '(') /* loop again on parenthesis. quote ends loop */
- X comment++;
- X else
- X comment--;
- X }
- X /* Something like ``Comment (Comment) <addr>''. In this case
- X * the name should include both comment parts with the
- X * parenthesis. We have to redo addr.
- X */
- X if ((p2 = any(p+1, "<,")) && *p2 == '<') {
- X if (!(p = index(p2, '>'))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (addr = beg_addr) { /* reassign addr and compare to null */
- X c = *p; *p = 0;
- X addr += Strcpy(addr, p2+1);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p = c;
- X }
- X if (name) {
- X c = *p2; *p2 = 0;
- X name += Strcpy(name, str);
- X while (name > beg_name && isspace(*(name-1)))
- X *--name = 0;
- X *p2 = c;
- X }
- X } else if (name && start[1]) {
- X c = *p, *p = 0; /* c may be ')' instead of '(' now */
- X name += Strcpy(name, start+1);
- X while (name > beg_name && isspace(*(name-1)))
- X *--name = 0;
- X *p = c;
- X }
- X }
- X skipspaces(1);
- X /* this is so common, save time by returning now */
- X if (!*p || *p == ',' || *p == '<')
- X return p;
- X return get_name_n_addr(p, name, addr);
- }
- X
- /* takes string 's' which can be a name or list of names separated by
- X * commas and checks to see if each is aliased to something else.
- X * return address of the static buf.
- X */
- char *
- alias_to_address(s)
- register char *s;
- {
- X static char buf[HDRSIZ];
- X register char *p, *p2, *tmp;
- X char newbuf[HDRSIZ], c;
- X static int recursive;
- X
- X if (!aliases)
- X return strcpy(buf, s);
- X if (!s || !*s)
- X return NULL;
- X if (!recursive) {
- X bzero(buf, sizeof buf);
- X p2 = buf; /* if we're starting all this, p2 starts at &buf[0] */
- X } else
- X p2 = buf+strlen(buf); /* else, pick up where we left off */
- X
- X if (++recursive == 30) {
- X wprint("alias references too many addresses!\n");
- X recursive = 0;
- X return NULL;
- X }
- X do {
- X char addr[256];
- X if (!(p = get_name_n_addr(s, NULL, addr)))
- X break;
- X c = *p, *p = 0;
- X
- X /* On recursive calls, compare against the entire
- X * previous expansion, not just the address part.
- X */
- X if (recursive > 1)
- X (void) strcpy(addr, s);
- X
- X /* if this is an alias, recurse this routine to expand it out */
- X if ((tmp = do_set(aliases, addr)) && *tmp) {
- X if (!alias_to_address(strcpy(newbuf, tmp))) {
- X *p = c;
- X return NULL;
- X } else
- X p2 = buf+strlen(buf);
- X /* Now, make sure the buffer doesn't overflow */
- X } else if (strlen(s) + (p2-buf) + 2 > sizeof buf) { /* add ", " */
- X wprint("address length too long.\n");
- X recursive = 0;
- X *p = c;
- X return NULL;
- X } else {
- X /* append the new alias (or unchanged address) onto the buffer */
- X p2 += Strcpy(p2, s);
- X *p2++ = ',', *p2++ = ' ', *p2 = '\0';
- X }
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(s = p));
- X if (recursive)
- X recursive--;
- X if (!recursive)
- X *(p2-2) = 0; /* get rid of last ", " if end of recursion */
- X return buf;
- }
- X
- /*
- X * Wrap addresses so that the headers don't exceed n chars (typically 80).
- X */
- char *
- wrap_addrs(str, n)
- char *str;
- {
- X char buf[HDRSIZ * 2], *start = str;
- X register char *b = buf, *p, c, *line_start = buf;
- X
- X *b = 0;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(str, NULL, NULL)))
- X break;
- X c = *p, *p = 0;
- X if (b > buf) {
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X if (b - line_start + strlen(str) + 8 /* \t = 8 */ >= n)
- X *b++ = '\n', *b++ = '\t', line_start = b;
- X }
- X for (b += Strcpy(b, str); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X return strcpy(start, buf);
- }
- SHAR_EOF
- echo 'File addrs.c is complete' &&
- chmod 0644 addrs.c ||
- echo 'restore of addrs.c failed'
- Wc_c="`wc -c < 'addrs.c'`"
- test 33326 -eq "$Wc_c" ||
- echo 'addrs.c: original size 33326, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= advanced.mushrc ==============
- if test -f 'advanced.mushrc' -a X"$1" != X"-c"; then
- echo 'x - skipping advanced.mushrc (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting advanced.mushrc (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'advanced.mushrc' &&
- # advanced.mushrc
- # by Bart Schaefer
- # with special thanks to Phil Lapsley <phil@east.Berkeley.EDU>, who
- # provided the original files on which this example is based. Most of
- # Phil's stuff is still here -- just reorganized and updated to use
- # mush 6.4 features that were unavailable when Phil did the originals.
- #
- # This file is intended to demonstrate helpful ways to use the
- # .mushrc, not advanced mush commands.
- X
- # The variable $thisfolder is always set EXCEPT when the .mushrc file
- # is read the first time. A test for non-existance of $thisfolder
- # allows the same .mushrc file to be sourced repeatedly without
- # redundant execution of the initialization commands.
- #
- if ! $?thisfolder
- X # Ignore the usual stuff
- X ignore received via message-id status priority
- X # Hide folders in ~/.mail and save read mail in spool
- X set folder=~/.mail hold
- X # Remember a few commands, set up editors, act like a shell
- X set history=20 editor=ex visual=vi unix
- X # Prompt has folder name, message number, history number
- X set prompt="%f %m (!) & "
- X # Header summaries show name, date, and subject
- X set hdr_format="%25n %-15d %27s"
- X # Initialize the cmds below (see later comments)
- X set first_time=1
- X
- X # These two commands are used for automated "bursting" of the spool
- X # mailbox. This means that the messages are reorganized into new
- X # folders to be read in a prearranged order. See comments below.
- X #
- X # n brings up the next folder, not the next message
- X cmd n 'source ~/.mushrc'
- X # N gets the next folder without "bursting"
- X cmd N 'set first_time=0; source ~/.mushrc'
- X
- X # Delete messages by pattern-matching. Examples:
- X # del f mailer-daemon Delete mail from mailer-daemon
- X # del t mush-users Delete mail to mush-users
- X cmd del 'pick -i -\!* | delete'
- X # Forwarding
- X cmd for 'mail -f'
- X # Quick folder change
- X cmd F 'folder'
- X
- X # Some useful aliases
- X alias dheller 'The Mush God <argv@sun.com>'
- X alias barts 'Archangel Mushael <schaefer@cse.ogi.edu>'
- X
- X # On init, don't source beyond this point
- X exit
- endif # End of init section -- read on startup only
- X
- # This part of the file handles "bursting". A burst is done when the
- # n cmd is used the first time. This is most useful if you habitually
- # have lots of mail when you first log in each morning; unwanted mail
- # can be deleted, and other mail organized for you.
- #
- # The folders in this example bursting scheme are:
- # mush-users anything to or cc'ed to mush-users
- # stats daily stats
- # root root mail other than daily stats
- # Mail not falling into one of these categories is left in the system
- # mailbox to be dealt with first.
- #
- if $first_time
- X # Kill off some uucp garbage
- X pick -i -s "file c.* delete" | delete
- X pick -i -s "file .* can.t access" | delete
- X pick -i -s "remote access to path/file denied" | delete
- X # Nuke the boring usenet stuff
- X pick -i -f usenet | pick -i -s "uucp map for" | delete
- X pick -i -t usenet | pick -i -s "returned mail" | delete
- X pick -i -t usenet | pick -i -s "automatic test echo" | delete
- X pick -i -t "owner-post" | pick -i -s "unknown mailer" | delete
- X pick -i -s "usenet disk space report" | delete
- X pick -i -s "very old news articles" | delete
- X pick -i -s "uucp map for" | delete
- X # Wipe out some uninteresting daily stats
- X pick -i -s "the maid was here." | delete
- X pick -i -s "daily accounting" | delete
- X pick -i -t netsurvey | delete
- X # Get rid of these things for good. This isn't essential, but
- X # avoids complexity in the later "pick" commands.
- X update
- X # Save anything "to" or "cc" to mush-users in that folder.
- X pick -i -t mush-users | save +mush-users
- X pick -i -h cc mush-users | save +mush-users
- X # Also save interesting daily stat mail and generic root mail
- X pick -i -f root | pick -i -s stats | save +stats
- X pick -i -f root | pick -i -s report | save +stats
- X pick -i -f uucp | pick -i -s report | save +stats
- X pick -i -f root | pick -i -s summary | save +stats
- X pick -i -f root | pick -i -s munge | save +stats
- X pick -i -t root | save +root
- X # Again, make the changes permanent. Saved mail gets deleted.
- X # This won't work if you have $keepsave set.
- X update
- X
- X # Make sure we don't burst again needlessly.
- X set first_time=0
- X
- X # Stop sourcing here. Otherwise, we'd change folders without
- X # handling the mail left in the system mailbox.
- X exit
- endif
- X
- # Finally, handle stepping through the folders one by one. This has been
- # set up for sendmail, where the system mailbox is /usr/spool/mail/$USER,
- # but could easily be modified for other mailers.
- #
- # $thisfolder:t returns the tail only of the folder name.
- X
- if $thisfolder:t == $USER
- X folder +stats
- X exit
- endif
- X
- if $thisfolder:t == stats
- X folder +mush-users
- X exit
- endif
- X
- if $thisfolder:t == mush-users
- X folder +root
- X exit
- endif
- X
- # Default back to the system mailbox
- folder %
- X
- # End of advanced.mushrc
- SHAR_EOF
- chmod 0644 advanced.mushrc ||
- echo 'restore of advanced.mushrc failed'
- Wc_c="`wc -c < 'advanced.mushrc'`"
- test 4976 -eq "$Wc_c" ||
- echo 'advanced.mushrc: original size 4976, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= bind.c ==============
- if test -f 'bind.c' -a X"$1" != X"-c"; then
- echo 'x - skipping bind.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting bind.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'bind.c' &&
- /* bind.c */
- X
- #include "bindings.h"
- #include "mush.h"
- X
- extern char *c_macro();
- static un_bind();
- X
- struct cmd_map *cmd_map, *line_map, *bang_map;
- X
- /*
- X * Bindings are added here in REVERSE of the order that
- X * they will be displayed! Display order is based on a
- X * guess about the frequency of use and (to a lesser
- X * extent) how hard they are to remember.
- X *
- X * The user's own new bindings, if any, will be displayed
- X * before any of these default bindings.
- X */
- init_bindings()
- {
- #ifdef CURSES
- X /* Help gets displayed last */
- X add_bind("?", C_HELP, NULL, &cmd_map);
- X add_bind("V", C_VERSION, NULL, &cmd_map);
- X
- X /* Miscellaneous shell commands */
- X add_bind("%", C_CHDIR, NULL, &cmd_map);
- X add_bind("|", C_PRINT_MSG, NULL, &cmd_map);
- X add_bind("!", C_SHELL_ESC, NULL, &cmd_map);
- X add_bind(":", C_CURSES_ESC, NULL, &cmd_map);
- X
- X /* Mush customization commands */
- X /* NOTE: No default C_MACRO bindings */
- X add_bind(")", C_SAVEOPTS, NULL, &cmd_map);
- X add_bind("(", C_SOURCE, NULL, &cmd_map);
- X add_bind("&!", C_MAP_BANG, NULL, &cmd_map);
- X add_bind("&:", C_MAP, NULL, &cmd_map);
- X add_bind("&&", C_BIND_MACRO, NULL, &cmd_map);
- X add_bind("v", C_VAR_SET, NULL, &cmd_map);
- X add_bind("i", C_IGNORE, NULL, &cmd_map);
- X add_bind("h", C_OWN_HDR, NULL, &cmd_map);
- X add_bind("B", C_UNBIND, NULL, &cmd_map);
- X add_bind("b", C_BIND, NULL, &cmd_map);
- X add_bind("a", C_ALIAS, NULL, &cmd_map);
- X
- X /* Display modification commands */
- X add_bind("\022", C_REVERSE, NULL, &cmd_map); /* ^R */
- X add_bind("\014", C_REDRAW, NULL, &cmd_map); /* ^L */
- X add_bind("Z", C_PREV_SCREEN, NULL, &cmd_map);
- X add_bind("z", C_NEXT_SCREEN, NULL, &cmd_map);
- X
- X /* Searching and sorting commands */
- X add_bind("\016", C_CONT_SEARCH, NULL, &cmd_map); /* ^N */
- X add_bind("\037", C_PREV_SEARCH, NULL, &cmd_map); /* ^/ */
- X add_bind("/", C_NEXT_SEARCH, NULL, &cmd_map);
- X add_bind("O", C_REV_SORT, NULL, &cmd_map);
- X add_bind("o", C_SORT, NULL, &cmd_map);
- X
- X /* Ways to get out */
- X add_bind("X", C_EXIT_HARD, NULL, &cmd_map);
- X add_bind("x", C_EXIT, NULL, &cmd_map);
- X add_bind("Q", C_QUIT_HARD, NULL, &cmd_map);
- X add_bind("q", C_QUIT, NULL, &cmd_map);
- X
- X /* Folder modification commands */
- X add_bind("\025", C_UPDATE, NULL, &cmd_map); /* ^U */
- X add_bind("\020", C_PRESERVE, NULL, &cmd_map); /* ^P */
- X add_bind("*", C_MARK_MSG, NULL, &cmd_map);
- X add_bind("W", C_WRITE_LIST, NULL, &cmd_map);
- X add_bind("w", C_WRITE_MSG, NULL, &cmd_map);
- X add_bind("U", C_UNDEL_LIST, NULL, &cmd_map);
- X add_bind("u", C_UNDEL_MSG, NULL, &cmd_map);
- X add_bind("S", C_SAVE_LIST, NULL, &cmd_map);
- X add_bind("s", C_SAVE_MSG, NULL, &cmd_map);
- X add_bind("f", C_FOLDER, NULL, &cmd_map);
- X add_bind("D", C_DELETE_LIST, NULL, &cmd_map);
- X add_bind("d", C_DELETE_MSG, NULL, &cmd_map);
- X add_bind("C", C_COPY_LIST, NULL, &cmd_map);
- X add_bind("c", C_COPY_MSG, NULL, &cmd_map);
- X
- X /* Cursor movement and message selection */
- X add_bind("g", C_GOTO_MSG, NULL, &cmd_map);
- X add_bind("}", C_BOTTOM_PAGE, NULL, &cmd_map);
- X add_bind("{", C_TOP_PAGE, NULL, &cmd_map);
- X add_bind("$", C_LAST_MSG, NULL, &cmd_map);
- X add_bind("^", C_FIRST_MSG, NULL, &cmd_map);
- X add_bind("\013",C_PREV_MSG, NULL, &cmd_map); /* ^K */
- X add_bind("\012", C_NEXT_MSG, NULL, &cmd_map); /* ^J */
- X add_bind("-",C_PREV_MSG, NULL, &cmd_map);
- X add_bind("+",C_NEXT_MSG, NULL, &cmd_map);
- X add_bind("K", C_PREV_MSG, NULL, &cmd_map);
- X add_bind("k", C_PREV_MSG, NULL, &cmd_map);
- X add_bind("J", C_NEXT_MSG, NULL, &cmd_map);
- X add_bind("j", C_NEXT_MSG, NULL, &cmd_map);
- X
- X /* Mail-sending commands */
- X add_bind("R", C_REPLY_ALL, NULL, &cmd_map);
- X add_bind("r", C_REPLY_SENDER, NULL, &cmd_map);
- X add_bind("M", C_MAIL_FLAGS, NULL, &cmd_map);
- X add_bind("m", C_MAIL, NULL, &cmd_map);
- X
- X /* Mail-reading commands */
- X add_bind(".", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("T", C_TOP_MSG, NULL, &cmd_map);
- X add_bind("t", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("p", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("n", C_DISPLAY_NEXT, NULL, &cmd_map);
- X
- #endif /* CURSES */
- }
- X
- /* Bindable function names.
- X * Most of these can't be used if CURSES is not defined,
- X * but help and lookups get confused if they aren't all here.
- X */
- struct cmd_map map_func_names[] = {
- X /* These MUST be in numerical order; see bindings.h */
- X { C_NULL, "no-op", NULL, NULL_MAP },
- X { C_GOTO_MSG, "goto-msg", NULL, NULL_MAP },
- X { C_WRITE_LIST, "write-list", NULL, NULL_MAP },
- X { C_WRITE_MSG, "write", NULL, NULL_MAP },
- X { C_SAVE_LIST, "save-list", NULL, NULL_MAP },
- X { C_SAVE_MSG, "save", NULL, NULL_MAP },
- X { C_COPY_LIST, "copy-list", NULL, NULL_MAP },
- X { C_COPY_MSG, "copy", NULL, NULL_MAP },
- X { C_DELETE_LIST, "delete-list", NULL, NULL_MAP },
- X { C_DELETE_MSG, "delete", NULL, NULL_MAP },
- X { C_UNDEL_LIST, "undelete-list", NULL, NULL_MAP },
- X { C_UNDEL_MSG, "undelete", NULL, NULL_MAP },
- X { C_REDRAW, "redraw", NULL, NULL_MAP },
- X { C_REVERSE, "reverse-video", NULL, NULL_MAP },
- X { C_NEXT_MSG, "next-msg", NULL, NULL_MAP },
- X { C_PREV_MSG, "back-msg", NULL, NULL_MAP },
- X { C_FIRST_MSG, "first-msg", NULL, NULL_MAP },
- X { C_LAST_MSG, "last-msg", NULL, NULL_MAP },
- X { C_TOP_PAGE, "top-page", NULL, NULL_MAP },
- X { C_BOTTOM_PAGE, "bottom-page", NULL, NULL_MAP },
- X { C_NEXT_SCREEN, "screen-next", NULL, NULL_MAP },
- X { C_PREV_SCREEN, "screen-back", NULL, NULL_MAP },
- X { C_SOURCE, "source", NULL, NULL_MAP },
- X { C_SAVEOPTS, "saveopts", NULL, NULL_MAP },
- X { C_NEXT_SEARCH, "search-next", NULL, NULL_MAP },
- X { C_PREV_SEARCH, "search-back", NULL, NULL_MAP },
- X { C_CONT_SEARCH, "search-again", NULL, NULL_MAP },
- X { C_PRESERVE, "preserve", NULL, NULL_MAP },
- X { C_REV_SORT, "sort-reverse", NULL, NULL_MAP },
- X { C_SORT, "sort", NULL, NULL_MAP },
- X { C_QUIT_HARD, "quit!", NULL, NULL_MAP },
- X { C_QUIT, "quit", NULL, NULL_MAP },
- X { C_EXIT_HARD, "exit!", NULL, NULL_MAP },
- X { C_EXIT, "exit", NULL, NULL_MAP },
- X { C_UPDATE, "update", NULL, NULL_MAP },
- X { C_FOLDER, "folder", NULL, NULL_MAP },
- X { C_SHELL_ESC, "shell-escape", NULL, NULL_MAP },
- X { C_CURSES_ESC, "line-mode", NULL, NULL_MAP },
- X { C_PRINT_MSG, "lpr", NULL, NULL_MAP },
- X { C_CHDIR, "chdir", NULL, NULL_MAP },
- X { C_VAR_SET, "variable", NULL, NULL_MAP },
- X { C_IGNORE, "ignore", NULL, NULL_MAP },
- X { C_ALIAS, "alias", NULL, NULL_MAP },
- X { C_OWN_HDR, "my-hdrs", NULL, NULL_MAP },
- X { C_VERSION, "version", NULL, NULL_MAP },
- X { C_MAIL_FLAGS, "mail-flags", NULL, NULL_MAP },
- X { C_MAIL, "mail", NULL, NULL_MAP },
- X { C_REPLY_ALL, "reply-all", NULL, NULL_MAP },
- X { C_REPLY_SENDER, "reply", NULL, NULL_MAP },
- X { C_DISPLAY_NEXT, "display-next", NULL, NULL_MAP },
- X { C_DISPLAY_MSG, "display", NULL, NULL_MAP },
- X { C_TOP_MSG, "top", NULL, NULL_MAP },
- X { C_BIND_MACRO, "bind-macro", NULL, NULL_MAP },
- X { C_BIND, "bind", NULL, NULL_MAP },
- X { C_UNBIND, "unbind", NULL, NULL_MAP },
- X { C_MAP_BANG, "map!", NULL, NULL_MAP },
- X { C_MAP, "map", NULL, NULL_MAP },
- X { C_MACRO, "macro", NULL, NULL_MAP },
- X { C_MARK_MSG, "mark", NULL, NULL_MAP },
- X /* C_HELP Must be the last one! */
- X { C_HELP, "help", NULL, NULL_MAP }
- };
- X
- #ifdef CURSES
- X
- /*
- X * getcmd() is called from curses mode only. It waits for char input from
- X * the user via m_getchar() (which means that a macro could provide input)
- X * and then compares the chars input against the "bind"ings set up by the
- X * user (or the defaults). For example, 'j' could bind to "next msg" which
- X * is interpreted by the big switch statement in curses_command() (curses.c).
- X * getcmd() returns the int-value of the curses command the input is "bound"
- X * to. If the input is unrecognized, C_NULL is returned (curses_command()
- X * might require some cleanup, so this is valid, too).
- X *
- X * Since the input could originate from a macro rather than the terminal,
- X * check to see if this is the case and search for a '[' char which indicates
- X * that there is a curses command or other "long" command to be executed.
- X */
- getcmd()
- {
- X char buf[MAX_BIND_LEN * 3];
- X register int c, m, match;
- X register char *p = buf;
- X register struct cmd_map *list;
- X
- X bzero(buf, MAX_BIND_LEN);
- X active_cmd = NULL_MAP;
- X c = m_getchar();
- X /* If user did job control (^Z), then the interrupt flag will be
- X * set. Be sure it's unset before continuing.
- X */
- X turnoff(glob_flags, WAS_INTR);
- X if (isdigit(c)) {
- X buf[0] = c;
- X buf[1] = '\0';
- X Ungetstr(buf); /* So mac_flush can clear on error */
- X return C_GOTO_MSG;
- X }
- X for (;;) {
- X if (ison(glob_flags, IN_MACRO) && c == MAC_LONG_CMD)
- X return long_mac_cmd(c, TRUE);
- X else
- X *p++ = c;
- X m = 0;
- X for (list = cmd_map; list; list = list->m_next) {
- X if ((match = prefix(buf, list->m_str)) == MATCH) {
- X if (debug)
- X print("\"%s\" ",
- X ctrl_strcpy(buf,
- X map_func_names[list->m_cmd].m_str,
- X TRUE));
- X if (list->m_cmd == C_MACRO) {
- X curs_macro(list->x_str);
- X return getcmd();
- X }
- X active_cmd = list;
- X return (int)list->m_cmd;
- X } else if (match != NO_MATCH)
- X m++;
- X }
- X if (m == 0) {
- X if (debug) {
- X char tmp[sizeof buf];
- X print("No binding for \"%s\" found.",
- X ctrl_strcpy(tmp, buf, TRUE));
- X }
- X return C_NULL;
- X }
- X c = m_getchar();
- X }
- }
- X
- #endif /* CURSES */
- X
- /*
- X * bind_it() is used to set or unset bind, map and map! settings.
- X * bind is used to accelerate curses commands by mapping key sequences
- X * to curses commands. map is used to accelerate command mode keysequences
- X * by simulating stdin. map! is the same, but used when in compose mode.
- X *
- X * bind_it() doesn't touch messages; return -1 for curses mode.
- X * return -2 to have curses command set CNTD_CMD to prevent screen refresh
- X * to allow user to read output in case of multiple lines.
- X *
- X * Since this routine deals with a lot of binding and unbinding of things
- X * like line-mode "map"s and is interactive (calls Getstr()), be very careful
- X * not to allow expansions during interaction.
- X */
- bind_it(len, argv)
- char **argv;
- {
- X char string[MAX_BIND_LEN], buf[256], *name = NULL;
- X char *rawstr; /* raw format of string (ptr to string if no argv avail) */
- X char ascii[MAX_BIND_LEN*2]; /* printable ascii version of string */
- X register int x;
- X SIGRET (*oldint)(), (*oldquit)();
- X struct cmd_map **map_list;
- X int unbind = (argv && **argv == 'u');
- X int map = 0, is_bind_macro = 0;
- X int ret = 0 - iscurses; /* return value */
- X
- X if (argv && !strcmp(name = *argv, "bind-macro"))
- X is_bind_macro++;
- X
- X if (map = (argv && (!strcmp(name, "map!") || !strcmp(name, "unmap!"))))
- X map_list = &bang_map;
- X else if (map = (argv && (!strcmp(name, "map") || !strcmp(name, "unmap"))))
- X map_list = &line_map;
- X else
- X map_list = &cmd_map;
- X
- X if (argv && *++argv && !strcmp(*argv, "-?"))
- X /* Subtract ret and iscurses to signal output */
- X return help(0, unbind? name+2 : name, cmd_help) - ret - iscurses;
- X
- X if (iscurses)
- X on_intr();
- X
- X if (unbind) {
- X if (!*argv) {
- X char savec = complete;
- X complete = 0;
- X print("%s what? ", name);
- X len = Getstr(buf, sizeof buf, 0);
- X complete = savec;
- X if (len <= 0) {
- X if (iscurses)
- X off_intr();
- X return -1;
- X }
- X rawstr = m_xlate(buf);
- X } else
- X rawstr = m_xlate(*argv);
- X if (!un_bind(rawstr, map_list)) {
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X print("\"%s\" isn't bound to a command.\n", ascii);
- X }
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X if (argv && *argv) {
- X rawstr = m_xlate(*argv);
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X if (!*++argv) {
- X /*
- X * determine whether "argv" references a "map" or a "bind"
- X */
- X int binding = c_bind(rawstr, *map_list);
- X if (binding == C_MACRO) {
- X char *mapping = c_macro(NULL, rawstr, *map_list);
- X if (mapping) {
- X print("\"%s\" is mapped to ", ascii);
- X print_more("\"%s\".\n",
- X ctrl_strcpy(buf, mapping, FALSE));
- X } else
- X print("\"%s\" isn't mapped.\n", ascii);
- X } else if (binding)
- X print("\"%s\" is %s to \"%s\".\n", ascii,
- X map? "mapped" : "bound", map_func_names[binding].m_str);
- X else if (map)
- X print("\"%s\" isn't mapped.\n", ascii);
- X else
- X print("\"%s\" isn't bound to a command.\n", ascii);
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X } else {
- X char savec = complete;
- X complete = 0;
- X print("%s [<CR>=all, -?=help]: ", name);
- X len = Getstr(string, MAX_BIND_LEN-1, 0);
- X complete = savec;
- X if (len == 0) {
- X int add_to_ret = iscurses;
- #ifdef CURSES
- X if (iscurses)
- X move(LINES-1, 0), refresh();
- #endif
- X if (map || is_bind_macro)
- X add_to_ret = !c_macro(name, NULL, *map_list);
- X else
- X add_to_ret = !c_bind(NULL, *map_list);
- X if (iscurses)
- X off_intr();
- X /* signal CTND_CMD if there was output */
- X return ret - add_to_ret;
- X }
- X if (len < 0) {
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X rawstr = m_xlate(string);
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X }
- X /* if a binding was given on the command line */
- X if (argv && *argv && !map)
- X if (is_bind_macro)
- X (void) strcpy(buf, "macro");
- X else
- X (void) strcpy(buf, *argv++);
- X else {
- X /* at this point, "rawstr" and "ascii" should both be set */
- X int binding;
- X
- X if (!strcmp(ascii, "-?")) {
- X if (iscurses)
- X clr_bot_line();
- X ret -= help(0, name, cmd_help);
- X if (iscurses)
- X off_intr();
- X /* Subtract iscurses to signal CNTD_CMD */
- X return ret - iscurses;
- X }
- X
- X if (!map && !is_bind_macro) {
- X binding = c_bind(rawstr, *map_list);
- X
- X for (len = 0; len == 0; ) {
- X print("\"%s\" = <%s>: New binding [<CR> for list]: ",
- X ascii, (binding? map_func_names[binding].m_str : "unset"));
- X len = Getstr(buf, sizeof buf, 0);
- X if (iscurses)
- X clr_bot_line();
- X /* strip any trailing whitespace */
- X if (len > 0)
- X len = no_newln(buf) - buf;
- X if (len == 0) {
- X (void) do_pager(NULL, TRUE);
- X if (iscurses)
- X putchar('\n');
- X for (x = 1; x <= C_HELP; x++) {
- X if (!(x % 4))
- X if (do_pager("\n", FALSE) == EOF)
- X break;
- X (void) do_pager(sprintf(buf, "%-15.15s ",
- X map_func_names[x].m_str), FALSE);
- X }
- X (void) do_pager("\n", FALSE);
- X (void) do_pager(NULL, FALSE);
- X ret -= iscurses;
- X }
- X }
- X } else /* map */
- X (void) strcpy(buf, "macro"), len = 5;
- X /* if list was printed, ret < -1 -- tells CNTD_CMD to be set and
- X * prevents screen from being refreshed (lets user read output
- X */
- X if (len == -1) {
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X }
- X for (x = 1; x <= C_HELP; x++) {
- X if (prefix(buf, map_func_names[x].m_str) == MATCH) {
- X int add_to_ret;
- X if (debug)
- X print("\"%s\" will execute \"%s\".\n", ascii, buf);
- X if (map_func_names[x].m_cmd == C_MACRO) {
- X if (argv && *argv) {
- X (void) argv_to_string(buf, argv);
- X (void) m_xlate(buf); /* Convert buf to raw chars */
- X add_to_ret =
- X do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
- X } else {
- X char exp[MAX_MACRO_LEN*2]; /* printable expansion */
- X char *mapping = c_macro(NULL, rawstr, *map_list);
- X
- X if (mapping)
- X (void) ctrl_strcpy(exp, mapping, TRUE);
- X print("\"%s\" = <%s>", ascii, mapping ? exp : "unset");
- X putchar('\n'), print("New macro: ");
- X ret -= iscurses; /* To signal screen messed up */
- X /* we are done with buf, so we can trash over it */
- X len = Getstr(buf, MAX_MACRO_LEN, 0);
- X if (len > 0) {
- X if (iscurses)
- X clr_bot_line();
- X (void) m_xlate(buf); /* Convert buf to raw chars */
- X add_to_ret =
- X do_bind(rawstr, C_MACRO, buf, map_list);
- X if (debug) {
- X (void) ctrl_strcpy(exp, buf, TRUE);
- X print("\"%s\" will execute \"%s\".\n", ascii, exp);
- X }
- X } else if (len < 0) {
- X if (iscurses)
- X off_intr();
- X return ret;
- X } else
- X print("Can't bind to null macro"), putchar('\n');
- X }
- X } else /* not a macro */ {
- X (void) argv_to_string(buf, argv);
- X add_to_ret =
- X do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
- X }
- X /* if do_bind had no errors, it returned -1. If we already
- X * messed up the screen, then ret is less than -1. return the
- X * lesser of the two to make sure that CNTD_CMD gets set right
- X */
- X if (iscurses)
- X off_intr();
- X return min(add_to_ret, ret);
- X }
- X }
- X print("\"%s\": Unknown function.\n", buf);
- X if (iscurses)
- X off_intr();
- X return ret;
- }
- X
- /*
- X * print current key to command bindings if "str" is NULL.
- X * else return the integer "m_cmd" which the str is bound to.
- X */
- c_bind(str, opts)
- register char *str;
- register struct cmd_map *opts;
- {
- X register int incurses = iscurses;
- X
- X if (!str) {
- X if (!opts) {
- X print("No command bindings.\n");
- X return C_ERROR;
- X }
- X if (incurses)
- X clr_bot_line(), iscurses = FALSE;
- X (void) do_pager(NULL, TRUE);
- X (void) do_pager("Current key to command bindings:\n", FALSE);
- X (void) do_pager("\n", FALSE);
- X }
- X
- X for (; opts; opts = opts->m_next) {
- X char buf[BUFSIZ], buf2[MAX_BIND_LEN], exp[MAX_MACRO_LEN*2], *xp;
- X if (!str) {
- X (void) ctrl_strcpy(buf2, opts->m_str, FALSE);
- X if ((xp = opts->x_str) && opts->m_cmd == C_MACRO)
- X xp = ctrl_strcpy(exp, opts->x_str, TRUE);
- X if (do_pager(sprintf(buf, "%s\t%-15.15s %s\n",
- X buf2, map_func_names[opts->m_cmd].m_str,
- X xp? xp : ""),
- X FALSE) == EOF)
- X break;
- X } else
- X if (strcmp(str, opts->m_str))
- X continue;
- X else
- X return opts->m_cmd;
- X }
- X
- X iscurses = incurses;
- X if (!str)
- X (void) do_pager(NULL, FALSE);
- X return C_NULL;
- }
- X
- /*
- X * Doesn't touch messages, but changes macros: return -1.
- X * Error output causes return < -1.
- X * args is currently the execute string of a macro mapping, but may be
- X * used in the future as an argument string for any curses command.
- X */
- do_bind(str, func, args, map_list)
- register char *str, *args;
- struct cmd_map **map_list;
- long func;
- {
- X register int ret = -1;
- X register struct cmd_map *list;
- X int match;
- X
- X if (func == C_MACRO && !check_mac_bindings(args))
- X --ret;
- X (void) un_bind(str, map_list);
- X for (list = *map_list; list; list = list->m_next)
- X if ((match = prefix(str, list->m_str)) != NO_MATCH) {
- X ret--;
- X switch (match) {
- X case MATCH:
- X puts("Something impossible just happened.");
- X when A_PREFIX_B:
- X wprint("Warning: \"%s\" prefixes \"%s\" (%s)\n", str,
- X list->m_str, map_func_names[list->m_cmd].m_str);
- X when B_PREFIX_A:
- X wprint("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
- X list->m_str, map_func_names[list->m_cmd].m_str, str);
- X }
- X }
- X add_bind(str, func, args, map_list);
- X /* errors decrement ret. If ret returns less than -1, CNTD_CMD is set
- X * and no redrawing is done so user can see the warning signs
- X */
- X return ret;
- }
- X
- /*
- X * add a binding to a list. This may include "map"s or other mappings since
- X * the map_list argument can control that. The "func" is an int defined in
- X * bindings.h ... the "str" passed is the string the user would have to type
- X * to get the macro/map/binding expanded. This must in in raw format: no
- X * \n's to mean \015. Convert first using m_xlate().
- X */
- add_bind(str, func, args, map_list)
- register char *str, *args;
- struct cmd_map **map_list;
- long func;
- {
- X register struct cmd_map *tmp;
- X
- X if (!str || !*str)
- X return;
- X
- X /* now make a new option struct and set fields */
- X if (!(tmp = (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
- X error("calloc");
- X return;
- X }
- X tmp->m_next = *map_list;
- X *map_list = tmp;
- X
- X tmp->m_str = savestr(str);
- X tmp->m_cmd = func; /* strdup handles the NULL case */
- X if (args && *args)
- X tmp->x_str = savestr(args);
- X else
- X tmp->x_str = NULL;
- }
- X
- static
- un_bind(p, map_list)
- register char *p;
- struct cmd_map **map_list;
- {
- X register struct cmd_map *list = *map_list, *tmp;
- X
- X if (!list || !*list->m_str || !p || !*p)
- X return 0;
- X
- X if (!strcmp(p, (*map_list)->m_str)) {
- X *map_list = (*map_list)->m_next;
- X xfree (list->m_str);
- X if (list->x_str)
- X xfree (list->x_str);
- X xfree((char *)list);
- X return 1;
- X }
- X for ( ; list->m_next; list = list->m_next)
- X if (!strcmp(p, list->m_next->m_str)) {
- X tmp = list->m_next;
- X list->m_next = list->m_next->m_next;
- X xfree (tmp->m_str);
- X if (tmp->x_str)
- X xfree (tmp->x_str);
- X xfree ((char *)tmp);
- X return 1;
- X }
- X return 0;
- }
- X
- prefix(a, b)
- register char *a, *b;
- {
- X if (!a || !b)
- X return NO_MATCH;
- X
- X while (*a && *b && *a == *b)
- X a++, b++;
- X if (!*a && !*b)
- X return MATCH;
- X if (!*a && *b)
- X return A_PREFIX_B;
- X if (*a && !*b)
- X return B_PREFIX_A;
- X return NO_MATCH;
- }
- SHAR_EOF
- chmod 0644 bind.c ||
- echo 'restore of bind.c failed'
- Wc_c="`wc -c < 'bind.c'`"
- test 20663 -eq "$Wc_c" ||
- echo 'bind.c: original size 20663, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= bindings.h ==============
- if test -f 'bindings.h' -a X"$1" != X"-c"; then
- echo 'x - skipping bindings.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting bindings.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'bindings.h' &&
- /* bindings.h -- command bindings */
- X
- #define MAX_BIND_LEN 20 /* max length a string can be to bind to a command */
- #define MAX_MACRO_LEN 256 /* max length of a macro bound to a command */
- X
- /* to see if a key sequence matches, prefixes or misses a set binding */
- #define NO_MATCH 0
- #define MATCH 1
- #define A_PREFIX_B 2
- #define B_PREFIX_A 3
- X
- /*
- X * Constants to define curses mode functions.
- X */
- #ifdef NULL_MAP
- #undef NULL_MAP
- #endif /* NULL_MAP */
- #define NULL_MAP (struct cmd_map *)0
- X
- #define C_ERROR (-1L)
- #define C_NULL 0L
- #define C_GOTO_MSG 1L
- #define C_WRITE_LIST 2L
- #define C_WRITE_MSG 3L
- #define C_SAVE_LIST 4L
- #define C_SAVE_MSG 5L
- #define C_COPY_LIST 6L
- #define C_COPY_MSG 7L
- #define C_DELETE_LIST 8L
- #define C_DELETE_MSG 9L
- #define C_UNDEL_LIST 10L
- #define C_UNDEL_MSG 11L
- #define C_REDRAW 12L
- #define C_REVERSE 13L
- #define C_NEXT_MSG 14L
- SHAR_EOF
- true || echo 'restore of bindings.h failed'
- fi
- echo 'End of part 3'
- echo 'File bindings.h is continued in part 4'
- echo 4 > _shar_seq_.tmp
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-